筆記目錄

Skip to content

如何在 Docker 使用 GitLab CI

在 Docker 上安裝 GitLab

參考官方文件,撰寫Docker Compose。

yaml
version: '3.7'

services:
  GitLab-Server:
    image: 'gitlab/gitlab-ee:latest'
    container_name: GitLab-Server
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://127.0.0.1:5080/'
        nginx['listen_port'] = 80
        gitlab_rails['gitlab_shell_ssh_port'] = 5022
    ports:
      - 5080:80
      - 5443:443
      - '5022:22'
    privileged: true
    volumes:
      - .\Volumes\GitLab-Server\Config:/etc/gitlab
      - data:/var/opt/gitlab
      - .\Volumes\GitLab-Server\Logs:/var/log/gitlab
    shm_size: '256m'
    networks:
      default:
        ipv4_address: 172.20.0.2
    restart: always
volumes:
  data:
networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.20.0.0/16
          gateway: 172.20.0.1
  1. 將指令游標切換至 docker-compose.yml 所在位置,並執行 docker-compose up -d 運行 Container。
  2. 稍等幾分鐘後,在網頁輸入「http://127.0.0.1:5080」訪問GitLab Web,帳號預設為 root,密碼則存放至檔案(/srv/gitlab/config/initial_root_password)裡。
  3. 點選右上角頭像 > preferences > password,將密碼改成好記的密碼,並重新登入。

TIP

  • external_url 不設定雖然可以連到網頁,但會有部分功能找不到網頁,且網域非所設定的 IP,而是一連串的英數字組合,或是在儲存庫上 SSH、http 裡記錄的複製儲存庫網址有這個問題。
  • external_url 最好設定成外部 IP 或是 Domain Name,這邊用 127.0.0.1 是因為雖然有指定 IP,但是無法使用主機使用設定 IP 連線(不過有時候設定又可能,暫時找不到原因)。
  • 當有設定 external_url 時,使用非 80 port,則要設定 nginx['listen_port'] = 80,如果是用 https ,則改為 443,詳細原因請參照此篇文章
  • 50xx 的 Port 可以自行視需求變更如果出現「invalid port specification」的錯誤訊息,參考 Invalid port specification: 601342,將5022:22用引號括起來。
  • external_urlgitlab_rails['gitlab_shell_ssh_port'] 的 port 設定與 ports 的對應關係要一致。
  • volumes 底下 /var/opt/gitlab 的路徑綁定,官網範例雖然是用「Bind Mount」,但在「artifacts」功能會因權限功能無法正常,所以是用「Volume」連結。

GitLab 的設置

GitLab 目前有提供兩種設定方式:

  1. gitlab.rb:存放在「/srv/gitlab/config/」底下,更改設定後,執行指令更新 GitLab 設定 gitlab-ctl reconfigure 來生效。
  2. Pre-configure:在 Docker 設定環境變數 GITLAB_OMNIBUS_CONFIG,此設定不會覆蓋 「gitlab.rb」,而是在每次執行 docker run 或是 docker-compose up 時,依所輸入的設定去更新 GitLab 設定,完整可支援的設定請參閱「gitlab.rb.template」。

在 Docker 上安裝 GitLab Runner

安裝方法可參考官方文件來設定 docker-compose,這邊將 GitLab Runner 的內容加至原先的 docker-compose.yml 裡面。

docker-compose.yml 裡 GitLab Runner的部分

yaml
services:
  GitLab-Server:
#...GitLab-Server的內容,這裡先省略...
  GitLab-Runner:
    image: gitlab/gitlab-runner:latest
    container_name: GitLab-Runner
    privileged: true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - .\Volumes\GitLab-Runner\Config:/etc/gitlab-runner
    networks:
      default:
        ipv4_address: 172.20.0.3
    restart: always
#...volumes和networks的內容,這裡先省略...

TIP

如果有使用Docker Executor的話需要設定 /var/run/docker.sock:/var/run/docker.sock

註冊 GitLab Runner

輸入指令 docker exec -it GitLab-Runner gitlab-runner register,其中字首大寫的「GitLab-Runner」為 在docker-compose 設定的 container_name,第二個全小寫的 gitlab-runner 為 gitlab-runner.exe。 當執行 Register 時,Command Line 會出現以下訊息,進行 Runner 的設定初始化。

  1. Enter the GitLab instance URL => 可讓 Runner 連上 GitLab 的網址,如上面範例為http://172.20.0.2。理論上複製 Token 頁面上會有網址可以複製,但是如果未設定 external_url 或是網址為 127.0.0.1localhost 之類的網址的話,那邊的網址無法正常使用。

  2. Enter the registration token => GitLab 有三種 Scope 的 Runner 類型可以註冊,可參閱「The scope of runners」,取得 Token 的位置如下表:

    Scope描述Token位置
    Shared Runner每個專案都可以使用。GitLab Admin Area > Overview > Runners > 點擊按鈕「Register an instance runner」則會顯示 Token。
    Group Runner僅供特定專案群組可以使用。CI/CD > Runners > 點擊按鈕「Register a group runner」則會顯示 Token。
    Project-Specific Runner只有指定專案可以使用。Settings > CI/CD > 展開 Runners > Specific runners 區塊有顯示 Token。
  3. Enter a description for the runner: 簡易輸入此 Runner 用途會做為此 Runner 的名稱,後面可在 GitLab 用戶界面中更改此值。

  4. Enter tags for the runner (comma-separated): 可輸入 Runner 的環境、Executor等內容,供後續 GitLab CI 在執行時,可以搜尋到符合的 Runner,後面可在 GitLab 用戶界面中更改此值。

  5. Enter optional maintenance note for the runner: 輸入一些給此 Runner 其他開發維護人員需了解的相關的資訊,可以輸入空白。

  6. Enter an executor: ssh, docker+machine, docker-ssh+machine, kubernetes, virtualbox, custom, docker, docker-ssh, parallels, shell: 輸入建構環境的方法,例如使用 docker 建置測試環境則輸入 docker,完整訊息請參閱Executors,另外如果 Runner 是安裝在 Windows 環境底下,還有 docker-windows 可以設定用來建置 Windows 平台的環境,不過目前支援環境不多。

  7. Enter the default Docker image: 如果輸入 docker 會顯示此訊息,輸入預設的 docker image,例如:docker:stable

設定完成後,會發現「\srv\gitlab-runner\config」產生一個檔案「config.toml」作為 Runner 的設定檔。如果更新設定檔後,正常是使用 gitlab-runner restart,但這邊 Runner 是建立在 Docker,官方是建議直接使用 docker restart GitLab-Runner 重啟 Container,GitLab-Runner 自行替換為自己設定的容器名稱。

各個平台註冊 Runner 的方法請參閱 Registering runners。 Runner 設定請參閱 Configuring GitLab Runner

簡單的 GitLab CI 實例 (Linux)

前置作業

  1. 建立一個 Repository 為「TestCore」。

  2. 將「TestCore」 Clone到本機。

  3. 在「TestCore」建立一個 .NET 6 的專案,資料結構如下:

    text
    TestCore
    │   .gitignore
    │   .gitlab-ci.yml
    │   README.md
    
    └───build
    │   │   Dockerfile
    
    └───src
    
        └───TestCore
            │   TestCore.sln
            │   TestCore
            │   ...
  4. 幫「TestCore」註冊一個使用 Docker Executor 的 Runner,tags 為dockerlinux,並開啟「config.toml」進行以下調整:

    • privileged 改為 true
    • volumes 改為 ["/var/run/docker.sock:/var/run/docker.sock", "/cache"],讓 Runner Executor 使用主機外部的 Docker Engine。
    • 如果 GitLab 未設定 external_url 或是設定為 127.0.0.1localhost 之類的,則須加上 clone_url
    • network_mode 設為 gitlab_default,讓 Runner Executor 可以用連到 GitLab。

完整內容如下:

text
concurrent = 1
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "Run Linux Docker"
  url = "http://172.20.0.2"
  id = 1
  token = "dayFwyc86q4TdQzYz_Ca"
  token_obtained_at = 2022-10-19T07:09:03Z
  token_expires_at = 0001-01-01T00:00:00Z
  clone_url = "http://172.20.0.2"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "docker:stable"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
    shm_size = 0
 network_mode = "gitlab_default"

WARNING

network_mode 不能設定成 host,否則 Runner 執行時,可能會造成 GitLab 忙碌無法回應。

Dockerfile內容

text
FROM mcr.microsoft.com/dotnet/sdk:6.0

WORKDIR /app
COPY ./publish ./

EXPOSE 80

ENV ASPNETCORE_URLS "http://+:80"

ENTRYPOINT ["dotnet", "TestCore.dll"]

.gitlab-ci.yml內容

yaml
stages:
  - build
  - list
  - deploy

build-job:
  stage: build
  image: mcr.microsoft.com/dotnet/sdk:6.0
  tags:
    - 'docker'
    - 'linux'
  script:
    - cd src/TestCore
    - dotnet restore
    - dotnet build --configuration Release
    - dotnet publish --configuration Release --output ../../build/publish
  artifacts:
    paths:
      - ./build/publish/*
    expire_in: never

list-job:
  stage: list
  image: bitnami/git:latest
  script:
    - git config --global core.quotepath false
    - git diff-tree -r --no-commit-id --name-status --diff-algorithm=minimal HEAD > changes.txt
  artifacts:
    paths:
      - ./changes.txt
    expire_in: never
  tags:
    - 'docker'
    - 'linux'

deploy-job:
  stage: deploy
  tags:
    - 'docker'
    - 'linux'
  variables:
    CONTAINER_RELEASE_IMAGE: $CI_PROJECT_PATH_SLUG:latest
  script:
    - cd build
    - docker build --tag $CONTAINER_RELEASE_IMAGE .
    - docker stop $CI_PROJECT_NAME || true && docker rm $CI_PROJECT_NAME || true
    - docker run -d -p 9080:80 --restart=always --name $CI_PROJECT_NAME $CONTAINER_RELEASE_IMAGE
  environment:
    name: production
    url: http://127.0.0.1:9080

.gitlab-ci.yml說明

這邊簡化分支部分,僅做一個簡化的流程範例

使用關鍵詞

  • stages:定義有哪些要執行的 Stage 名稱和順序,名稱可自己設定。
  • job:範例中的 build-jobdeploy-job,名稱可自己設定。
    • stage:設定此 Job 屬於 stages 裡的哪個 Stage。
    • tags:設定執行的 Runner,例如我這邊設定dockerlinux,那就會只有設定dockerlinux 的 Runner 會執行,若找不到符合 Runner,則會停擺直到 timeout。
    • image:因為是使用 Docker Executor,每個 Stage 都為一個 Docker Container,所以要設定此 Stage 所使用的 Image 環境,如果沒設定,就會使用 Runner 設定的 Default Image。
    • variables:變數宣告。
    • script:要在 Runner 裡執行的 Command Script。
    • artifacts:設定成功後附加到作業的文件和目錄列表,由於每階段是獨立的 Container,所以執行後把像是編譯過後的程式進行上傳,在從下個 Stage 下載使用。
    • paths:要上傳的檔案路徑。
      • expire_in:保留時間。
    • environment:要部署的環境設定
      • name:環境名稱。
      • 給外面連結 Url。

流程說明

build-job
  1. 設定使用 Image 為 mcr.microsoft.com/dotnet/sdk:6.0,這邊最好和 Dockerfile 用的 Image 一致。
  2. State 開始時,會從 Repository 下載此次上傳版本的檔案、資料夾。
  3. 因為 Repository 的專案資料夾是放在 src/方案目錄/專案目錄,所以先用 cd 切換目錄到方案目錄底下,如果有多專案,則切換到要選擇的專案資料夾底下。
  4. 使用 dotnet restore 做套件還原,不過官網說執行 docker build 會自動進行 dotnet restore
  5. 使用 - dotnet build --configuration Release,建置專案,因為這邊是範例,所以configuration 直接設定為 Release,實務上應搭配分支決定 configuration。
  6. - dotnet publish --configuration Release --output ../../build/publish 發佈專案,並指定輸出資料夾。
  7. artifacts 設定要保留的路徑檔案和時間。
list-job
  1. 使用 git config --global core.quotepath false 來停止轉譯特殊字符,在輸出路徑時,中文會被當成特殊字符轉換掉,所以將 core.quotepath 設為 false

  2. 產出異動清單,Command 說明如下:

    • git diff-tree:透過比較兩個節點的樹對象,找到的差異的內容和模式,如果只輸入一個節點,則比較此節點與其父節點比較。
    • -r:遞歸到子樹,若未設定只會比較一層。
    • --no-commit-id:不顯示 Commit ID。
    • --name-status:僅顯示更改文件的名稱和狀態。
    • --diff-algorithm=minimal:選擇差異算法,使用最小差異。
    • HEAD:當前分支的最後一次提交

如果需要針對匯出格式調整,請參考官方文章 diff-tree

deploy-job
  1. 未設定 Image,所以會使用 Runner 定義的 docker:stable

  2. State 開始時,除了下載 Repository 的檔案外,會額外將前面 artifacts 設定的路徑檔案下載下來至「build/publish」底下,所以 build 結構如下。

    text
    build
    │   Dockerfile(來自Repository)
    
    └───publish/*(來自artifacts)
  3. 切換目錄至「build」。

  4. 使用 docker build 將 Dockerfile 和 「publish」底下檔案建置成 image可執行 Web 的image。

  5. 嘗試移除同名的 Container。

  6. 使用 docker run 將剛建置的 image 來啟動 Container。

  7. environment 將 Container 裡的 Web Url 提供給部署裡的環境設定。

執行結果

CI/CD > Jobs

如果 State 有上傳檔案至 artifacts 裡,會出現可下載圖示,藍框可以下載異動清單,紅框可下載編譯後檔案。

gitlab artifact download interface

Deployments > Environments

會顯示一個可用環境,點擊「開啟」後,會開啟網址為 http://127.0.0.1:9080 的網頁,不從這邊開啟,直接輸入網址也可以。

gitlab environment interface

WARNING

  1. 網路有些做法是用 Docker in Docker(DIND),使用的Docker Image Tag會是 dind 結尾,不過此法建立的 Container 我不知要如何讓外部使用,所以選擇在 Runner 的「config.toml」裡,將 volumes 增加 docker.sock 的對應,此法會讓建立的 Image 和 Container 都掛載在外部的 Docker 底下。
  2. 「CI_」開頭的變數為系統內部變數,詳情參考 Predefined variables reference
  3. 官網範例在建立 Image 是使用「CI_REGISTRY」開頭的變數,因為要啟用 Registry 相關功能要走 https,且要建立相應的 Access Token 才可使用,這邊就不提了。
  4. Image 名稱只能為小寫,因為範例裡的 Repository 名稱有含大寫,所以使用CI_PROJECT_PATH_SLUG

參考資料來源

The .gitlab-ci.yml fileEnvironments and deploymentsgitlab-ci build asp.net core docker.Net & Docker(一)在Docker容器上運行.Net Core API

異動歷程

  • 2022-10-24 初版文件建立。